home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 031a / adg_1_3.zip / VOYEUR.C < prev    next >
C/C++ Source or Header  |  1991-02-21  |  24KB  |  705 lines

  1. /****************************************************************************
  2. Module name: Voyeur.C
  3. Programmer : Jeffrey M. Richter.
  4. *****************************************************************************/
  5.  
  6. #include "..\nowindws.h"
  7. #undef NOCOLOR
  8. #undef NOCTLMGR
  9. #undef NOGDI
  10. #undef NOKERNEL
  11. #undef NOLSTRING
  12. #undef NOMB
  13. #undef NOMENUS
  14. #undef NOMINMAX
  15. #undef NOMSG
  16. #undef NORASTEROPS
  17. #undef NOSHOWWINDOW
  18. #undef NOSYSMETRICS
  19. #undef NOUSER
  20. #undef NOWINOFFSETS
  21. #undef NOWINMESSAGES
  22. #undef NOWINSTYLES
  23. #include <windows.h>
  24.  
  25. #include "voyeur.h"
  26.  
  27. char _szAppName[] = "Voyeur";
  28.  
  29. HANDLE _hInstance = NULL;  // Our instance handle
  30. HWND _hWndStats = NULL;
  31.  
  32. #define IDM_PEERINTOWINDOW       (0x0110)   // Must be < 0xF000 (GetSystemMenu)
  33. #define IDM_DROPBACKANDPEER      (0x0120)   // Must be < 0xF000
  34. #define IDM_ABOUT                (0x0130)   // Must be < 0xF000
  35.  
  36.  
  37. typedef struct { DWORD dwID; char *szName; } STYLELIST;
  38.  
  39. STYLELIST _ClassStyles[] = {
  40.    { CS_VREDRAW,           "VREDRAW"               },
  41.    { CS_HREDRAW,           "HREDRAW"               },
  42.    { CS_KEYCVTWINDOW,      "KEYCVTWINDOW"          },
  43.    { CS_DBLCLKS,           "DBLCLKS"               },
  44.    { 0x0010,               "OEMCHARS"              }, // Windows 2.x
  45.    { CS_OWNDC,             "OWNDC"                 },
  46.    { CS_CLASSDC,           "CLASSDC"               },
  47.    { CS_PARENTDC,          "PARENTDC"              },
  48.    { CS_NOKEYCVT,          "NOKEYCVT"              },
  49.    { CS_NOCLOSE,           "NOCLOSE"               },
  50.    { CS_SAVEBITS,          "SAVEBITS"              },
  51.    { CS_BYTEALIGNCLIENT,   "BYTEALIGNCLIENT"       },
  52.    { CS_BYTEALIGNWINDOW,   "BYTEALIGNWINDOW"       },
  53.    { CS_GLOBALCLASS,       "GLOBALCLASS"           },
  54.    { 0,                    NULL                    }
  55. };
  56.  
  57. STYLELIST _WindowStyles[] = {
  58.    { WS_POPUP,             "POPUP"                 },
  59.    { WS_CHILD,             "CHILD"                 },
  60.    { WS_MINIMIZE,          "MINIMIZE"              },
  61.    { WS_VISIBLE,           "VISIBLE"               },
  62.    { WS_DISABLED,          "DISABLED"              },
  63.    { WS_CLIPSIBLINGS,      "CLIPSIBLINGS"          },
  64.    { WS_CLIPCHILDREN,      "CLIPCHILDREN"          },
  65.    { WS_MAXIMIZE,          "MAXIMIZE"              },
  66.    { WS_BORDER,            "BORDER"                },
  67.    { WS_DLGFRAME,          "DLGFRAME"              },
  68.    { WS_VSCROLL,           "VSCROLL"               },
  69.    { WS_HSCROLL,           "HSCROLL"               },
  70.    { WS_SYSMENU,           "SYSMENU"               },
  71.    { WS_THICKFRAME,        "THICKFRAME"            },
  72.    { WS_GROUP,             "GROUP, MINIMIZEBOX"    },
  73.    { WS_TABSTOP,           "TABSTOP, MAXIMIZEBOX"  },
  74.    { 0,                    NULL                    }
  75. };
  76.  
  77. STYLELIST _ExtWindowStyles[] = {
  78.    { WS_EX_DLGMODALFRAME,  "DLGMODALFRAME"         },
  79.    { WS_EX_NOPARENTNOTIFY, "NOPARENTNOTIFY"        },
  80.    { 0,                    NULL                    }
  81. };
  82.  
  83.  
  84. typedef enum {
  85.    CIH_ICON, CIH_CURSOR, CIH_BACKGROUND, CIH_WNDPROC, CIH_MENU, CIH_END
  86. } CLASSINFOHEAD;
  87.  
  88. char *szClassInfoHeading[] = {
  89.    "Icon: ",
  90.    "Cursor: ",
  91.    "Backgrnd: ",
  92.    "WndProc: ",
  93.    "Menu: ",
  94.    NULL
  95. };
  96.  
  97.  
  98.  
  99. BOOL NEAR PASCAL RegisterAppWndClass (HANDLE hInstance);
  100. BOOL FAR PASCAL AboutProc (HWND hDlg, WORD wMsg, WORD wParam, LONG lParam);
  101. BOOL FAR PASCAL ForcePeer (HWND hDlg, WORD wMsg, WORD wParam, LONG lParam);
  102. LONG FAR PASCAL VoyeurAppWndProc (HWND hWnd, WORD wMsg, WORD wParam, LONG lParam);
  103.  
  104.  
  105. // ***************************************************************************
  106. int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) {
  107.    MSG msg;
  108.    HWND hWnd;
  109.  
  110.    _hInstance = hInstance;
  111.  
  112.    if (hPrevInstance == NULL)
  113.       if (!RegisterAppWndClass(hInstance))
  114.          return(0);
  115.  
  116.    hWnd = CreateWindow(_szAppName, _szAppName,
  117.       WS_OVERLAPPED | WS_VISIBLE | WS_CLIPCHILDREN |
  118.       WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 
  119.       CW_USEDEFAULT, nCmdShow, CW_USEDEFAULT, CW_USEDEFAULT,
  120.       NULL, NULL, hInstance, 0);
  121.  
  122.    if (hWnd == NULL) return(0);
  123.  
  124.    while (GetMessage(&msg, NULL, 0, 0)) {
  125.       if (!IsDialogMessage(_hWndStats, &msg)) {
  126.          TranslateMessage(&msg);
  127.          DispatchMessage(&msg);
  128.       }
  129.    }
  130.  
  131.    return(0);
  132. }
  133.  
  134.  
  135.  
  136. // ***************************************************************************
  137. // This function registers Voyeur's main window.
  138.  
  139. BOOL NEAR PASCAL RegisterAppWndClass (HANDLE hInstance) {
  140.    WNDCLASS WndClass;
  141.  
  142.    WndClass.style         = 0;
  143.    WndClass.lpfnWndProc   = VoyeurAppWndProc;
  144.    WndClass.cbClsExtra    = 0;
  145.    WndClass.cbWndExtra    = 0;
  146.    WndClass.hInstance     = hInstance;
  147.    WndClass.hIcon         = LoadIcon(hInstance, _szAppName);
  148.    WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  149.    WndClass.hbrBackground = COLOR_WINDOW + 1;
  150.    WndClass.lpszMenuName  = NULL;
  151.    WndClass.lpszClassName = _szAppName;
  152.    return(RegisterClass(&WndClass));
  153. }
  154.  
  155.  
  156. // ***************************************************************************
  157. // This function processes all messages sent to the modeless dialog box.
  158.  
  159. BOOL FAR PASCAL VoyeurDlgProc (HWND hDlg, WORD wMsg, WORD wParam, LONG lParam) {
  160.    BOOL fProcessed = TRUE;
  161.    WORD wTextLen, wMaxTextLen = 0, wTabStop;
  162.    NPSTR szHeading; HDC hDC;
  163.    CLASSINFOHEAD ClassInfoHead;
  164.    HWND hWndOtherBox;
  165.  
  166.    switch (wMsg) {
  167.       case WM_INITDIALOG:
  168.          // Determine where to place tabstop in listbox.
  169.  
  170.          hWndOtherBox = GetDlgItem(hDlg, ID_CLASSOTHERBOX);
  171.          hDC = GetDC(hWndOtherBox);
  172.  
  173.          for (ClassInfoHead = 0; ClassInfoHead != CIH_END; ClassInfoHead++) {
  174.             szHeading = szClassInfoHeading[ClassInfoHead];
  175.  
  176.             // Get length (in pixels) of heading.
  177.             wTextLen = LOWORD(GetTextExtent(hDC, szHeading,
  178.                         lstrlen(szHeading)));
  179.  
  180.             // Find heading with maximum length.
  181.             wMaxTextLen = max(wMaxTextLen, wTextLen);
  182.          }
  183.          ReleaseDC(hWndOtherBox, hDC);
  184.  
  185.          // Convert pixels into dialog units.
  186.          wTabStop = 4 + wMaxTextLen / (LOWORD(GetDialogBaseUnits()) / 4);
  187.  
  188.          // Set tabstop position in listbox.  Note: listbox must have
  189.          // LBS_USETABSTOPS style in dialog box template.
  190.          SendMessage(hWndOtherBox, LB_SETTABSTOPS, 1,
  191.             (LONG) (WORD FAR *) &wTabStop);
  192.  
  193.          fProcessed = FALSE;
  194.          break;
  195.  
  196.       default:
  197.          fProcessed = FALSE;
  198.          break;
  199.    }
  200.  
  201.    return(fProcessed);
  202. }
  203.  
  204.  
  205.  
  206. // ***************************************************************************
  207. // This function fills a listbox with the text names of the styles.
  208. // It is used for the class styles, window styles, and extended 
  209. // window styles.
  210.  
  211. void NEAR PASCAL FillStyleBox (HWND hListBox, STYLELIST Styles[],
  212.                                DWORD dwStyleFlags) {
  213.    int x;
  214.  
  215.    // Turn off redraw so that the listbox will not flicker every time
  216.    // an entry is added to it.  This also makes updating much faster.
  217.    SendMessage(hListBox, WM_SETREDRAW, FALSE, 0);
  218.  
  219.    // Empty the listbox.
  220.    SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
  221.  
  222.    for (x = 0; Styles[x].szName != NULL; x++) {
  223.  
  224.       if (Styles[x].dwID & dwStyleFlags) {
  225.          // If the style bit is set, add the style text to the listbox.
  226.          SendMessage(hListBox, LB_ADDSTRING, 0,
  227.             (LONG) (LPSTR) Styles[x].szName);
  228.       }
  229.    }
  230.  
  231.    // Turn redraw back on.
  232.    SendMessage(hListBox, WM_SETREDRAW, TRUE, 0);
  233.  
  234.    // Force redraw of listbox so that screen shows proper information.
  235.    InvalidateRect(hListBox, NULL, TRUE);
  236. }
  237.  
  238.  
  239.  
  240. // ***************************************************************************
  241. // This function sets all of the static and listbox windows with the class
  242. // information about the passed-in window (hWnd).  
  243.  
  244. void NEAR PASCAL SetClassInfo (HWND hDlg, HWND hWnd) {
  245.    char szText[100], szBuf[100];
  246.    WNDCLASS WndClass;
  247.    WORD x;
  248.  
  249.    // Get the class name of the window.
  250.    GetClassName(hWnd, szBuf, sizeof(szBuf));
  251.    SetDlgItemText(hDlg, ID_CLASSNAME, szBuf);
  252.    
  253.    // Fill a WNDCLASS structure.
  254.    GetClassInfo(GetClassWord(hWnd, GCW_HMODULE), szBuf, &WndClass);
  255.    WndClass.hInstance = GetClassWord(hWnd, GCW_HMODULE);
  256.  
  257.    // Get the module name of the application that registered this class.
  258.    GetModuleFileName(WndClass.hInstance, szText, sizeof(szText));
  259.    wsprintf(szBuf, "0x%04X, %s", WndClass.hInstance, (LPSTR) szText);
  260.    SetDlgItemText(hDlg, ID_OWNER, szBuf);
  261.  
  262.  
  263.    // Fill the "Other" listbox with information from WNDCLASS structure.
  264.  
  265.    SendDlgItemMessage(hDlg, ID_CLASSOTHERBOX, WM_SETREDRAW, FALSE, 0);
  266.    SendDlgItemMessage(hDlg, ID_CLASSOTHERBOX, LB_RESETCONTENT, 0, 0);
  267.  
  268.    wsprintf(szBuf, "%s\t0x%04X",
  269.       (LPSTR) szClassInfoHeading[CIH_ICON], WndClass.hIcon);
  270.    SendDlgItemMessage(hDlg, ID_CLASSOTHERBOX, LB_ADDSTRING, 0,
  271.       (LONG) (LPSTR) szBuf);
  272.  
  273.    wsprintf(szBuf, "%s\t0x%04X",
  274.       (LPSTR) szClassInfoHeading[CIH_CURSOR], WndClass.hCursor);
  275.    SendDlgItemMessage(hDlg, ID_CLASSOTHERBOX, LB_ADDSTRING, 0,
  276.       (LONG) (LPSTR) szBuf);
  277.  
  278.    wsprintf(szBuf, "%s\t0x%04X",
  279.       (LPSTR) szClassInfoHeading[CIH_BACKGROUND], WndClass.hbrBackground);
  280.    SendDlgItemMessage(hDlg, ID_CLASSOTHERBOX, LB_ADDSTRING, 0,
  281.       (LONG) (LPSTR) szBuf);
  282.  
  283.    wsprintf(szBuf, "%s\t0x%04X:0x%04X",
  284.       (LPSTR) szClassInfoHeading[CIH_WNDPROC],
  285.       HIWORD(WndClass.lpfnWndProc), LOWORD((LONG) WndClass.lpfnWndProc));
  286.    SendDlgItemMessage(hDlg, ID_CLASSOTHERBOX, LB_ADDSTRING, 0,
  287.       (LONG) (LPSTR) szBuf);
  288.  
  289.    wsprintf(szBuf, "%s\t0x%04X:0x%04X",
  290.       (LPSTR) szClassInfoHeading[CIH_MENU],
  291.       HIWORD(WndClass.lpszMenuName), LOWORD((LONG) WndClass.lpszMenuName));
  292.    SendDlgItemMessage(hDlg, ID_CLASSOTHERBOX, LB_ADDSTRING, 0,
  293.       (LONG) (LPSTR) szBuf);
  294.  
  295.    SendDlgItemMessage(hDlg, ID_CLASSOTHERBOX, WM_SETREDRAW, TRUE, 0);
  296.    InvalidateRect(GetDlgItem(hDlg, ID_CLASSOTHERBOX), NULL, TRUE);
  297.  
  298.    // Fill in all the "Class style" information.
  299.    wsprintf(szBuf, "0x%04X", WndClass.style);
  300.    SetDlgItemText(hDlg, ID_CLASSSTYLE, szBuf);
  301.  
  302.    // Fill the "Class style" listbox with information from WndClass.style.
  303.    FillStyleBox(GetDlgItem(hDlg, ID_CLASSSTYLEBOX),
  304.       _ClassStyles, WndClass.style);
  305.  
  306.  
  307.    // Fill in all the "Class extra byte" information.
  308.    wsprintf(szBuf, "%d", WndClass.cbClsExtra);
  309.    SetDlgItemText(hDlg, ID_CBCLSEXTRA, szBuf);
  310.  
  311.    // Fill the "Class extra bytes" listbox.
  312.    SendDlgItemMessage(hDlg, ID_CBCLSEXTRABOX, WM_SETREDRAW, FALSE, 0);
  313.    SendDlgItemMessage(hDlg, ID_CBCLSEXTRABOX, LB_RESETCONTENT, 0, 0);
  314.  
  315.    for (x = 0; x < (WORD) WndClass.cbClsExtra; x++) {
  316.       wsprintf(szBuf, "%02d)  0x%02X", x, LOBYTE(GetClassWord(hWnd, x)));
  317.       SendDlgItemMessage(hDlg, ID_CBCLSEXTRABOX, LB_ADDSTRING, 0,
  318.          (LONG) (LPSTR) szBuf);
  319.    }
  320.    
  321.    SendDlgItemMessage(hDlg, ID_CBCLSEXTRABOX, WM_SETREDRAW, TRUE, 0);
  322.  
  323.    // Force redraw of "Class extra bytes" listbox.
  324.    InvalidateRect(GetDlgItem(hDlg, ID_CBCLSEXTRABOX), NULL, TRUE);
  325. }
  326.  
  327. // ***************************************************************************
  328. // This function sets all of the static and listbox windows with the window
  329. // information about the passed-in window (hWnd).  
  330.  
  331. void NEAR PASCAL SetWindowInfo (HWND hDlg, HWND hWnd) {
  332.    char szText[100], szBuf[100];
  333.    HANDLE hInstance;
  334.    FARPROC lpfnWndProc;
  335.    HWND hWndParent;
  336.    RECT rc;
  337.    WORD x, cbWndExtra;
  338.  
  339.    // Get caption of "peered" window.
  340.    if (GetWindowText(hWnd, szText, sizeof(szText)) == 0)
  341.       lstrcpy(szText, "(no caption)");
  342.    wsprintf(szBuf, "0x%04X, %s", hWnd, (LPSTR) szText);
  343.    SetDlgItemText(hDlg, ID_WINDOW, szBuf);
  344.  
  345.    // Get module name of application that created this window.
  346.    hInstance = GetWindowWord(hWnd, GWW_HINSTANCE);
  347.    if (GetModuleFileName(hInstance, szText, sizeof(szText)) == 0)
  348.       lstrcpy(szText, "(no module name)");
  349.    wsprintf(szBuf, "0x%04X, %s", hInstance, (LPSTR) szText);
  350.    SetDlgItemText(hDlg, ID_CREATOR, szBuf);
  351.  
  352.    // If window has a parent, get the parent's information.
  353.    hWndParent = GetParent(hWnd);
  354.    if (hWndParent == NULL)
  355.       lstrcpy(szBuf, "(no parent window)");
  356.    else {
  357.       if (GetWindowText(hWndParent, szText, sizeof(szText)) == 0)
  358.          lstrcpy(szText, "(no caption)");
  359.       wsprintf(szBuf, "0x%04X, %s", hWndParent, (LPSTR) szText);
  360.    }
  361.    SetDlgItemText(hDlg, ID_PARENT, szBuf);
  362.  
  363.    // Get address of window's window procedure.
  364.    lpfnWndProc = (FARPROC) GetWindowLong(hWnd, GWL_WNDPROC);
  365.    wsprintf(szBuf, "0x%04X:0x%04X",
  366.       HIWORD(lpfnWndProc), LOWORD((LONG) lpfnWndProc));
  367.    SetDlgItemText(hDlg, ID_WNDPROC, szBuf);
  368.  
  369.    // Get window's ID.
  370.    wsprintf(szBuf, "0x%04X  (%d)", GetWindowWord(hWnd, GWW_ID),
  371.       GetWindowWord(hWnd, GWW_ID));
  372.    SetDlgItemText(hDlg, ID_ID, szBuf);
  373.  
  374.    // Get screen coordinates of window.  
  375.    // Show (left, top)-(right, bottom),  Dim=Width x Height
  376.    GetWindowRect(hWnd, &rc);
  377.    wsprintf(szBuf, "(%d, %d)-(%d, %d),  Dim=%dx%d",
  378.       rc.left, rc.top, rc.right, rc.bottom,
  379.       rc.right - rc.left, rc.bottom - rc.top);
  380.    SetDlgItemText(hDlg, ID_LOCATION, szBuf);
  381.  
  382.  
  383.    // Fill in all the "Window style" information.
  384.    wsprintf(szBuf, "0x%08lX", GetWindowLong(hWnd, GWL_STYLE));
  385.    SetDlgItemText(hDlg, ID_WNDSTYLES, szBuf);
  386.  
  387.    // Fill the "Window style" listbox.
  388.    FillStyleBox(GetDlgItem(hDlg, ID_WNDSTYLESBOX),
  389.       _WindowStyles, GetWindowLong(hWnd, GWL_STYLE));
  390.  
  391.  
  392.  
  393.    // Fill in all the "Extended window style" information.
  394.    wsprintf(szBuf, "0x%08lX", GetWindowLong(hWnd, GWL_EXSTYLE));
  395.    SetDlgItemText(hDlg, ID_WNDEXTSTYLES, szBuf);
  396.  
  397.    // Fill the "Extended window style" listbox.
  398.    FillStyleBox(GetDlgItem(hDlg, ID_WNDEXTSTYLESBOX),
  399.       _ExtWindowStyles, GetWindowLong(hWnd, GWL_EXSTYLE));
  400.  
  401.  
  402.  
  403.  
  404.    // Fill in all the "Window extra byte" information.
  405.    cbWndExtra = GetClassWord(hWnd, GCW_CBWNDEXTRA);
  406.    wsprintf(szBuf, "%d", cbWndExtra);
  407.    SetDlgItemText(hDlg, ID_CBWNDEXTRA, szBuf);
  408.  
  409.    // Fill the "Window extra bytes" listbox.
  410.    SendDlgItemMessage(hDlg, ID_CBWNDEXTRABOX, WM_SETREDRAW, FALSE, 0);
  411.    SendDlgItemMessage(hDlg, ID_CBWNDEXTRABOX, LB_RESETCONTENT, 0, 0);
  412.  
  413.    for (x = 0; x < cbWndExtra; x++) {
  414.       wsprintf(szBuf, "%02d)  0x%02X", x, LOBYTE(GetWindowWord(hWnd, x)));
  415.       SendDlgItemMessage(hDlg, ID_CBWNDEXTRABOX, LB_ADDSTRING, 0,
  416.          (LONG) (LPSTR) szBuf);
  417.    }
  418.  
  419.    SendDlgItemMessage(hDlg, ID_CBWNDEXTRABOX, WM_SETREDRAW, TRUE, 0);
  420.  
  421.    // Force redraw of "Window extra bytes" listbox.
  422.    InvalidateRect(GetDlgItem(hDlg, ID_CBWNDEXTRABOX), NULL, TRUE);
  423. }
  424.  
  425. // ***************************************************************************
  426. // This functions draw a frame around a given window.  The frame is drawn
  427. // in the inverse screen color.  This allows a second call to this function
  428. // to restore the screen display to its original appearance.
  429.  
  430. void NEAR PASCAL DrawWindowFrame (HWND hWnd) {
  431.    HDC  hDC;
  432.    RECT rc;
  433.    HPEN hPen;
  434.  
  435.    // Retrieve location of window on screen
  436.    GetWindowRect(hWnd, &rc);
  437.  
  438.    // Get a Device context that allows us to write anywhere within the
  439.    // window.  NOTE: GetDC would only allow us to write in the window's
  440.    // client area.
  441.    hDC = GetWindowDC(hWnd);
  442.  
  443.    // To guarantee that the frame will be visible, tell Windows to
  444.    // draw the frame using the inverse screen color.
  445.    SetROP2(hDC, R2_NOT);
  446.  
  447.    // Create a pen that is 3 times the width on a non-sizeable border
  448.    // think.  The color will not be used to draw the frame, so its 
  449.    // value could be anything.  PS_INSIDEFRAME tells windows that the 
  450.    // entire frame should be enclosed within the window.
  451.    hPen = CreatePen(PS_INSIDEFRAME, 3 * GetSystemMetrics(SM_CXBORDER),
  452.       RGB(0, 0, 0));
  453.    SelectObject(hDC, hPen);
  454.  
  455.    // We must select a NULL brush so that the contents of the window
  456.    // will not be covered.
  457.    SelectObject(hDC, GetStockObject(NULL_BRUSH));
  458.  
  459.    // Draw the frame.  Because the Device Context is relative to 
  460.    // the window, the left-top corner is (0, 0) and the right-bottom
  461.    // corner is (width of window, height of window)
  462.    Rectangle(hDC, 0, 0, rc.right - rc.left, rc.bottom - rc.top);
  463.  
  464.    ReleaseDC(hWnd, hDC);
  465.  
  466.    // We can only destroy the pen AFTER we have released the Device Context
  467.    // because the DC must have valid "tools" in it at all times.
  468.    DeleteObject(hPen);
  469. }
  470.  
  471. // ***************************************************************************
  472. // This function processes all messages sent to Voyeur's main window.
  473.  
  474. LONG FAR PASCAL VoyeurAppWndProc (HWND hWnd, WORD wMsg, WORD wParam, LONG lParam) {
  475.    BOOL fOk, fCallDefProc = FALSE;
  476.    LONG lResult = 0;
  477.    HMENU hMenu;
  478.    RECT rc, rcStatDlg;
  479.    FARPROC fpProc;
  480.    HWND hWndSubject, hWndChild;
  481.    static HWND hWndLastSubject = NULL;
  482.  
  483.    switch (wMsg) {
  484.  
  485.       case WM_NCCREATE:
  486.          // Allow Windows to allocate memory for window.
  487.          fOk = (BOOL) DefWindowProc(hWnd, wMsg, wParam, lParam);
  488.  
  489.          if (!fOk) {
  490.             // Windows couldn't create the window, return.
  491.             lResult = 0;
  492.             break;
  493.          }
  494.  
  495.          // Try to create modeless dialog box.
  496.          _hWndStats = CreateDialog(_hInstance, "VOYEUR", hWnd,
  497.             MakeProcInstance(VoyeurDlgProc, _hInstance));
  498.  
  499.          if (_hWndStats == NULL) {
  500.  
  501.             // If modeless dialog box couldn't be created, tell
  502.             // Windows to free memory for window and return.
  503.             DefWindowProc(hWnd, WM_NCDESTROY, 0, 0);
  504.             lResult = 0;
  505.             break;
  506.          }
  507.  
  508.          // Change Voyeur's window dimensions so that it exactly
  509.          // surrounds the modeless dialog box.  Voyeur's position 
  510.          // on the screen should not be altered.
  511.          GetWindowRect(hWnd, &rc);
  512.          GetWindowRect(_hWndStats, &rcStatDlg);
  513.          MoveWindow(hWnd, rc.left, rc.top,
  514.             rcStatDlg.right - rcStatDlg.left,
  515.             rcStatDlg.bottom - rcStatDlg.top + GetSystemMetrics(SM_CYCAPTION),
  516.             FALSE);
  517.  
  518.          // Get handle to Voyeur's System Menu.
  519.          hMenu = GetSystemMenu(hWnd, 0);
  520.  
  521.          // Append separator bar & two options.
  522.          AppendMenu(hMenu, MF_SEPARATOR, 0, 0);
  523.          AppendMenu(hMenu, MF_STRING,
  524.             IDM_PEERINTOWINDOW, "&Peer into window");
  525.          AppendMenu(hMenu, MF_STRING,
  526.             IDM_DROPBACKANDPEER, "&Drop back and peer");
  527.  
  528.          // Append separator bar & "About..." option.
  529.          AppendMenu(hMenu, MF_SEPARATOR, 0, 0);
  530.          AppendMenu(hMenu, MF_STRING, IDM_ABOUT, "A&bout...");
  531.          DrawMenuBar(hWnd);
  532.  
  533.          lResult = 1;   // Window has been created OK.
  534.          break;
  535.  
  536.       case WM_DESTROY:
  537.          PostQuitMessage(0);
  538.          break;
  539.  
  540.       case WM_SYSCOMMAND:
  541.          // Any menu option selected from Voyeur's System Menu.
  542.  
  543.          // Any option's that we appended to System menu should be
  544.          // processed by Voyeur and NOT passed to DefWindowProc.
  545.  
  546.          switch (wParam & 0xfff0) {
  547.  
  548.          case IDM_ABOUT:
  549.             // Display Voyeur's about box
  550.             fpProc = MakeProcInstance(AboutProc, _hInstance);
  551.             DialogBox(_hInstance, "About", hWnd, fpProc);
  552.             FreeProcInstance(fpProc);
  553.             break;
  554.  
  555.  
  556.          case IDM_DROPBACKANDPEER:
  557.             // Send Voyeur's window to back of Window Manager's list
  558.             // This causes any windows that are overlapped by Voyeur
  559.             // to become visible.  This allows these windows to be
  560.             // "peered" into.
  561.             SetWindowPos(hWnd, 1, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  562.  
  563.             // Fall through to IDM_PEERINTOWINDOW
  564.  
  565.  
  566.          case IDM_PEERINTOWINDOW:
  567.             // Force all mouse messages to arrive at this window procedure.
  568.             SetCapture(hWnd);
  569.  
  570.             // Change the mouse cursor to a pair of eyes.  This provides a
  571.             // visual indication to the user that Voyeur is in "peer" mode.
  572.             SetCursor(LoadCursor(_hInstance, "Eyes"));
  573.  
  574.             // Set the Window handle of the last viewed window to NULL.
  575.             hWndLastSubject = NULL;
  576.             break;
  577.  
  578.          default:
  579.             // Any option's that we do not process should be 
  580.             // passed to DefWindowProc.
  581.             fCallDefProc = TRUE;
  582.             break;
  583.          }
  584.  
  585.          break;
  586.  
  587.  
  588.       case WM_MOUSEMOVE:
  589.          // If we don't have capture, we shouldn't do anything.
  590.          if (GetCapture() == NULL)
  591.             break;
  592.  
  593.          // lParam contains the mouse location relative to Voyeur's 
  594.          // client area.
  595.  
  596.          // Convert the location to screen coordinates
  597.          ClientToScreen(hWnd, &MAKEPOINT(lParam));
  598.  
  599.          // Get the window handle of the window under the mouse cursor.
  600.          hWndSubject = WindowFromPoint(MAKEPOINT(lParam));
  601.  
  602.          // If mouse isn't over a window, return
  603.          if (hWndSubject == NULL) break;
  604.  
  605.          // If window as created by Voyeur, ignore it.
  606.          if (GetWindowTask(hWndSubject) == GetCurrentTask())
  607.             break;
  608.  
  609.          // Convert the mouse location into client coordinates relative
  610.          // to the window that is under the mouse cursor.
  611.          ScreenToClient(hWndSubject, &MAKEPOINT(lParam));
  612.  
  613.          // Get the window handle of the child window under the mouse cursor.
  614.          hWndChild = ChildWindowFromPoint(hWndSubject, MAKEPOINT(lParam));
  615.  
  616.          // If point is over a child, our subject is the child window
  617.          if (hWndChild != NULL)
  618.             hWndSubject = hWndChild;
  619.  
  620.          // If our new subject is the same as our last subject, there is
  621.          // no need to update our display.
  622.          if (hWndLastSubject == hWndSubject)
  623.             break;
  624.  
  625.          // If this is not our first window being viewed, remove the
  626.          // frame surrounding the previously viewed window.
  627.          if (hWndLastSubject != NULL)
  628.             DrawWindowFrame(hWndLastSubject);
  629.  
  630.          UpdateWindow(hWndSubject);
  631.  
  632.          // Draw a frame around our new window.
  633.          DrawWindowFrame(hWndSubject);
  634.  
  635.          // Fill our status box with the subject window's class information.
  636.          SetClassInfo(_hWndStats, hWndSubject);
  637.  
  638.          // Fill our status box with the subject window's window information.
  639.          SetWindowInfo(_hWndStats, hWndSubject);
  640.  
  641.          hWndLastSubject = hWndSubject;
  642.          break;
  643.  
  644.  
  645.       case WM_LBUTTONUP:
  646.          // If we don't have capture, we shouldn't do anything.
  647.          if (GetCapture() != hWnd)
  648.             break;
  649.  
  650.          // If we never "peered" into a window, we don't have to remove
  651.          // its surrounding frame.
  652.          if (hWndLastSubject != NULL)
  653.             DrawWindowFrame(hWndLastSubject);
  654.  
  655.          // Allow other applications to receive mouse messages.
  656.          ReleaseCapture();
  657.  
  658.          // Force Voyeur to appear on top of all other windows.
  659.          BringWindowToTop(hWnd);
  660.          
  661.          break;
  662.  
  663.       default:
  664.          fCallDefProc = TRUE; break;
  665.    }
  666.  
  667.    if (fCallDefProc)
  668.       lResult = DefWindowProc(hWnd, wMsg, wParam, lParam);
  669.  
  670.    return(lResult);
  671. }
  672.  
  673. // ***************************************************************************
  674. // This function processes all messages sent to the About dialog box.
  675.  
  676. BOOL FAR PASCAL AboutProc (HWND hDlg, WORD wMsg, WORD wParam, LONG lParam) {
  677.    char szBuffer[100];
  678.    BOOL fProcessed = TRUE;
  679.  
  680.    switch (wMsg) {
  681.  
  682.       case WM_INITDIALOG:
  683.          // Set version static window to have date and time of compilation.
  684.          wsprintf(szBuffer, "%s at %s", (LPSTR) __DATE__, (LPSTR) __TIME__);
  685.          SetWindowText(GetDlgItem(hDlg, ID_VERSION), szBuffer);
  686.          break;
  687.  
  688.       case WM_COMMAND:
  689.          switch (wParam) {
  690.             case IDOK: case IDCANCEL:
  691.                if (HIWORD(lParam) == BN_CLICKED)
  692.                   EndDialog(hDlg, wParam);
  693.                break;
  694.  
  695.             default:
  696.                break;
  697.          }
  698.          break;
  699.  
  700.       default:
  701.          fProcessed = FALSE; break;
  702.    }
  703.    return(fProcessed);
  704. }
  705.